/*
  强制门户 测试
*/

#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>

const char* AP_SSID = "TestGate";        //这里改成你的AP名字--AP账号
const char* AP_PSW = "12345678";         //这里改成你的AP密码 8位以上

//配网页面代码
const char* page_html = "\
<!DOCTYPE html>\r\n\
<html lang='en'>\r\n\
<head>\r\n\
  <meta charset='UTF-8'>\r\n\
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>\r\n\
  <title>Switch</title>\r\n\
  <style>\r\n\
    body {\r\n\
      background-color: rgb(247, 250, 95);\r\n\
    }\r\n\
    .box {\r\n\
      width: 200px;\r\n\
      height: 110px;\r\n\
      background-color: rgb(92, 134, 250);\r\n\
      border: 4px solid gray;\r\n\
      position: absolute;\r\n\
      left: 50%;\r\n\
      top: 50%;\r\n\
      margin-top: -55px;\r\n\
      margin-left: -100px;\r\n\
      border-radius: 10px;\r\n\
      font-size: 70px;\r\n\
      font-weight: 500;\r\n\
      color: white;\r\n\
      outline: none;\r\n\
    }\r\n\
  </style>\r\n\
</head>\r\n\
<body>\r\n\
  <form name='input' action='/SWITCH' method='POST' >\r\n\
    <input type='submit' value='开/关' class='box'><br>\r\n\
  </form>\r\n\
</body>\r\n\
</html>\r\n\
";
const char* page_success_html = "\
<!DOCTYPE html>\r\n\
<html lang='en'>\r\n\
<head>\r\n\
  <meta charset='UTF-8'>\r\n\
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>\r\n\
  <title>Switch</title>\r\n\
  <style>\r\n\
    body {\r\n\
      background-color: rgb(247, 250, 95);\r\n\
    }\r\n\
    .box {\r\n\
      width: 200px;\r\n\
      height: 110px;\r\n\
      background-color: rgb(92, 134, 250);\r\n\
      border: 4px solid gray;\r\n\
      position: absolute;\r\n\
      left: 50%;\r\n\
      top: 50%;\r\n\
      margin-top: -55px;\r\n\
      margin-left: -100px;\r\n\
      border-radius: 10px;\r\n\
      font-size: 40px;\r\n\
      font-weight: 400;\r\n\
      color: white;\r\n\
      outline: none;\r\n\
    }\r\n\
  </style>\r\n\
</head>\r\n\
<body>\r\n\
  <form name='input' action='/SUCCESS' method='POST' >\r\n\
    <input type='submit' value='操作成功' class='box'><br>\r\n\
  </form>\r\n\
</body>\r\n\
</html>\r\n\
";

const byte DNS_PORT = 53;       //DNS端口号
IPAddress apIP(192, 168, 4, 1); //esp8266-AP-IP地址
DNSServer dnsServer;            //创建dnsServer实例
ESP8266WebServer server(80);    //创建WebServer

void handleRoot() {//访问主页回调函数
  server.send(200, "text/html", page_html);
}

//Post回调函数:处理LED控制请求
void handleRootPost() {
  digitalWrite(D5,!digitalRead(D5));// 改变LED的点亮或者熄灭状态
  //server.sendHeader("Location",page_success_html);// 跳转回页面根目录
  server.send(200, "text/html", page_success_html);
  server.send(303);                 // 发送Http相应代码303 跳转  
  Serial.println("/SWITCH 请求");
}

void handleRootSuccess() {//访问主页回调函数
  server.send(200, "text/html", page_html);
  Serial.println("/SUCCESS请求");
}

//初始化基础
void initBasic(void){
  Serial.begin(115200);
  pinMode(D5, OUTPUT); //设置D5引脚为输出模式以便控制LED
}

//初始化AP模式
void initSoftAP(void){
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  if(WiFi.softAP(AP_SSID,AP_PSW)){
    Serial.println("ESP8266 SoftAP is right");
  }
}

//初始化WebServer
void initWebServer(void){
  /*必须在第二个参数上添加上HTTP_GET才能不影响强制门户，防止有些设备无法弹出强制门户，要用域名访问,
    如果不加第二个参数，就只能实现域名访问而无法强制门户
    在无法响应的http请求响应回调设置为主页的回调函数，才可以强制门户*/
  server.on("/", HTTP_GET, handleRoot);//设置主页回调函数
  server.onNotFound(handleRoot);//设置无法响应的http请求的回调函数
  server.on("/SWITCH", HTTP_POST, handleRootPost);//设置Post请求回调函数
  server.on("/SUCCESS", HTTP_POST, handleRootSuccess);//设置Post请求回调函数
  server.begin();//启动WebServer
  Serial.println("WebServer started!");
}

void initDNS(void){//初始化DNS服务器
  if(dnsServer.start(DNS_PORT, "*", apIP)){//判断将所有地址映射到esp8266的ip上是否成功
    Serial.println("start dnsserver success.");
  }
  else Serial.println("start dnsserver failed.");
}

void connectNewWifi(void){
  WiFi.setAutoConnect(true);//设置自动连接(经过测试，强制门户必须要加上这一句)
  //WiFi.begin();             //(经过测试，强制门户必须要加上这一句，我并没有找到原因)
  int count = 0;
   while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    count++;
    if(count > 10){//如果5秒内没有连上，就开启Web配网 可适当调整这个时间
      initSoftAP();
      initWebServer();
      initDNS();
      break;//跳出 防止无限初始化
    }
    Serial.print(".");
  }
}

void setup() {
  initBasic();
  connectNewWifi();
}

void loop() {
  server.handleClient();
  dnsServer.processNextRequest();
}
